package de.hpi.generator.config;

import java.util.ArrayList;

/**
 * a dependency models collection
 * @author Michael Wolowyk
 */
public class DependencyModels extends ArrayList<DependencyModel> {
    private static final long serialVersionUID = 1L;

    /**
     * normalize Inclusion Dependency Models
     * @return Normalized Inclusion Dependency Models
     */
    public DependencyModels getNormalizedInclusionDependencyModels() {
        DependencyModels result = new DependencyModels();

        for (DependencyModel aInclusionDependencyModel : this) {
            
            if (isCompositeInclusionDependency(aInclusionDependencyModel)) {
                DependencyModel aCompositeDependency = normalizeCompositeInclusionDependency(aInclusionDependencyModel);
                result.addUniqueItem(aCompositeDependency);
            } 
            else {
                DependencyModels aSingleDepencySet = generateSingleDepencySet(aInclusionDependencyModel);
                result.addUniqueItems(aSingleDepencySet);
            }
        }
        return result;
    }

    /**
     * checks if Inclusion Dependency Model is composite
     * @param aInclusionDependencyModel
     * @return true if composite, otherwise false
     */
    protected boolean isCompositeInclusionDependency(DependencyModel aInclusionDependencyModel) {
        return aInclusionDependencyModel.dependent.contains("(") || aInclusionDependencyModel.referenced.contains("(");
    }

    /**
     * normalize composite Inclusion Dependency model
     * @param aInclusionDependencyModel
     * @return a normalized composite inclusion dependency model
     */
    protected DependencyModel normalizeCompositeInclusionDependency(DependencyModel aInclusionDependencyModel) {
        String aDependent = aInclusionDependencyModel.dependent.replace("(", "").replace(")", "");
        String aReferenced = aInclusionDependencyModel.referenced.replace("(", "").replace(")", "");

        DependencyModel result = new DependencyModel(aDependent, aReferenced, aInclusionDependencyModel.distribution);
        result.setComposite(true);
        return result;
    }

    /**
     * add all splited dependency models to collection if not exists
     * @param aDepencySet models to add
     */
    protected void addUniqueItems(DependencyModels aDepencySet) {
        for (DependencyModel aDependency : aDepencySet) {
            addUniqueItem(aDependency);
        }
    }

    /**
     * add a single splited dependency model to collection if not exists
     * @param aDependency a model to add
     */
    protected void addUniqueItem(DependencyModel aDependency) {
        if (!isExists(aDependency)) {
            this.add(aDependency);
        }
    }

    /**
     * checks if inclusion dependency model exists in this collection
     * @param aInclusionDependencyModel a model to check
     * @return true if exists, otherwise false
     */
    protected boolean isExists(DependencyModel aInclusionDependencyModel) {
        for (DependencyModel aTestObject : this) {
            if (aTestObject.dependent.compareTo(aInclusionDependencyModel.dependent) == 0
                    && aTestObject.referenced.compareTo(aInclusionDependencyModel.referenced) == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * split inclusion dependency strings to separate models
     * @param aInclusionDependencyModel
     * @return separated models
     */
    protected DependencyModels generateSingleDepencySet(DependencyModel aInclusionDependencyModel) {
        DependencyModels result = new DependencyModels();

        String[] aDependentParts = aInclusionDependencyModel.dependent.replace(" ", "").split(",");
        String[] aReferencedParts = aInclusionDependencyModel.referenced.replace(" ", "").split(",");
        for (String aDependentPart : aDependentParts) {
            for (String aReferencedPart : aReferencedParts) {
                if (aDependentPart.compareTo(aReferencedPart) != 0) {
                    result.add(new DependencyModel(aDependentPart, aReferencedPart));
                }
            }
        }
        return result;
    }
}
